package DyingBaby.backend.dm.logger;

import DyingBaby.utils.Panic;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import DyingBaby.common.Error;
import DyingBaby.utils.Parser;

/**
 * 日志记录器接口
 * 提供日志记录、读取和管理功能，用于数据恢复和持久化
 */
public interface Logger {
    // 将数据记录到日志中
    void log(byte[] data);

    // 截断日志到指定位置x
    void truncate(long x) throws Exception;

    // 读取下一条日志记录
    byte[] next();

    // 将日志指针重置到开始位置
    void rewind();

    // 关闭日志文件
    void close();

    /**
     * 创建新的日志文件
     * @param path 日志文件路径（不包含后缀）
     * @return Logger实例
     */
    public static Logger create(String path) {
        // 创建文件对象，添加日志文件后缀
        File f = new File(path+LoggerImpl.LOG_SUFFIX);
        try {
            // 尝试创建新文件，如果文件已存在则报错
            if(!f.createNewFile()) {
                Panic.panic(Error.FileExistsException);
            }
        } catch (Exception e) {
            Panic.panic(e);
        }
        // 检查文件读写权限
        if(!f.canRead() || !f.canWrite()) {
            Panic.panic(Error.FileCannotRWException);
        }

        FileChannel fc = null;
        RandomAccessFile raf = null;
        try {
            // 以读写模式打开随机访问文件
            raf = new RandomAccessFile(f, "rw");
            // 获取文件通道
            fc = raf.getChannel();
        } catch (FileNotFoundException e) {
            Panic.panic(e);
        }

        // 创建包含整数0的字节缓冲区（可能用于初始化文件头）
        ByteBuffer buf = ByteBuffer.wrap(Parser.int2Byte(0));
        try {
            // 定位到文件开头
            fc.position(0);
            // 写入初始数据
            fc.write(buf);
            // 强制将数据写入磁盘
            fc.force(false);
        } catch (IOException e) {
            Panic.panic(e);
        }

        // 创建Logger实现实例，初始位置为0
        return new LoggerImpl(raf, fc, 0);
    }

    /**
     * 打开已存在的日志文件
     * @param path 日志文件路径（不包含后缀）
     * @return Logger实例
     */
    public static Logger open(String path) {
        // 创建文件对象，添加日志文件后缀
        File f = new File(path+LoggerImpl.LOG_SUFFIX);
        // 检查文件是否存在
        if(!f.exists()) {
            Panic.panic(Error.FileNotExistsException);
        }
        // 检查文件读写权限
        if(!f.canRead() || !f.canWrite()) {
            Panic.panic(Error.FileCannotRWException);
        }

        FileChannel fc = null;
        RandomAccessFile raf = null;
        try {
            // 以读写模式打开随机访问文件
            raf = new RandomAccessFile(f, "rw");
            // 获取文件通道
            fc = raf.getChannel();
        } catch (FileNotFoundException e) {
            Panic.panic(e);
        }

        // 创建Logger实现实例
        LoggerImpl lg = new LoggerImpl(raf, fc);
        // 初始化日志读取器（可能读取文件头等信息）
        lg.init();

        return lg;
    }
}